package pl.edu.mimuw.mas.agent;

import jade.core.AID;

import java.util.HashSet;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import pl.edu.mimuw.mas.agent.behaviour.DFRegisterBehaviour;
import pl.edu.mimuw.mas.agent.behaviour.helicopter.BroadcastDeerPositionBehaviour;
import pl.edu.mimuw.mas.agent.behaviour.helicopter.PatrolBehaviour;
import pl.edu.mimuw.mas.agent.behaviour.helicopter.areaassignment.LeaderSequentialBehaviour;
import pl.edu.mimuw.mas.agent.behaviour.helicopter.areaassignment.ListenSearchAreaBehaviour;
import pl.edu.mimuw.mas.agent.behaviour.helicopter.areaassignment.SendPositionToLeaderBehaviour;
import pl.edu.mimuw.mas.agent.behaviour.helicopter.verification.BestAgentPickerBehaviour;
import pl.edu.mimuw.mas.agent.behaviour.helicopter.verification.FollowDeerBehaviour;
import pl.edu.mimuw.mas.agent.behaviour.helicopter.verification.SendCfpBehaviour;
import pl.edu.mimuw.mas.agent.behaviour.helicopter.verification.SendOfferServerBehaviour;
import pl.edu.mimuw.mas.agent.behaviour.helicopter.verification.VerifyBehaviour;
import pl.edu.mimuw.mas.chart.Area;
import pl.edu.mimuw.mas.chart.Chart;
import pl.edu.mimuw.mas.message.PositionMessage;
import pl.edu.mimuw.mas.util.AgentColor;
import pl.edu.mimuw.mas.util.PositionHelper;

/**
 * Agent powietrzny, celem tego agenta jest odnalezienie łosia. Agent przyjmuje
 * trzy agrumenty pierwszy nazwę lidera, drugi mapa, trzeci ilość helikopterów.
 */
public class HelicopterAgent extends AbstractAgent {
	private static final long serialVersionUID = 5208354843249834270L;

	public static final String SERVICE_TYPE = "helicopter-service";
	
	public static final String HELICOPTER_TELL_POSITION_TO_LEADER_CONV = "helicopter-tell-position-to-leader-conv";
	public static final String HELICOPTER_ASSIGN_SEARCH_AREA_CONV = "helicopter-assign-search-area-conv";
	public static final String HELICOPTER_VERIFY_CONV = "helicopter-check-cfp-conv";

	public static final int PATROL = 4;
	public static final int FOLLOW = 8;
	public static final int PRE_VERIFY = 16;
	public static final int VERIFY = 32;
	public static final int BROADCAST = 64;
	
	
	private final Logger logger = LoggerFactory.getLogger(getClass());
	
	private Area searchArea;
	private AID leaderAID;
	private boolean leader;
	private int agentCount;
	
	private HashSet<PositionMessage> agents;

	private int status;
	private PatrolBehaviour patrol;
	private FollowDeerBehaviour follow;
	
	protected void setup() {
		logger.info("{} : aktywny", getName());

		if (!setServiceAgents()) {
			doDelete();
			return;
		}

		setLanguages();
		
		Object[] obj = getArguments();
		try {
			leaderAID = new AID((String) obj[0], true);
			chart = (Chart) obj[1];
			agentCount = (Integer) obj[2];		
		} catch (Exception e) {
			logger.error("{}: Błąd podczas inicjalizacji", getName(), e);
			doDelete();
			return;
		}

		leader = getAID().equals(leaderAID);
		position = PositionHelper.getRandomPositionInAir(this);

		setColor();
		
		//
		// Zachowania
		//
		
		addBehaviour(new DFRegisterBehaviour(this, SERVICE_TYPE));
		
		if (leader) {
			logger.info("{}: Jestem liderem", getName());
			addBehaviour(new LeaderSequentialBehaviour(this, agentCount));
		} else {
			addBehaviour(new SendPositionToLeaderBehaviour(this, leaderAID, position));
		}
		
		addBehaviour(new ListenSearchAreaBehaviour(this, leaderAID));
		addBehaviour(new SendOfferServerBehaviour(this));
	}

	protected void takeDown() {
		logger.info("{} : papa", getName());
		log("wychodzi z gry");
	}
	
	//
	// Zmiana stanu agenta
	//

	public void doPatrol() {
		if(status == VERIFY) {
			// patrol.init();
		} else if(status == FOLLOW) {
			// patrol.init();
			removeBehaviour(follow);
		}
		
		status = PATROL;
		
		logger.debug("{}: Zmiana stanu na PATROL", getName());
		log("Zmiana stanu na PATROL");
		
		if(patrol == null) {
			patrol = new PatrolBehaviour(this, searchArea);
		}
		
		addBehaviour(patrol);
	}
	
	public void doFollow() {		
		if(status == PATROL) {
			removeBehaviour(patrol);
			
			status = FOLLOW;
			
			logger.debug("{}: Zmiana stanu na FOLLOW", getName());
			log("Zmiana stanu na FOLLOW");

			if(follow == null) {
				follow = new FollowDeerBehaviour(this);	
			}
			addBehaviour(follow);

			addBehaviour(new SendCfpBehaviour(this));
			addBehaviour(new BestAgentPickerBehaviour(this));
		} else {
			logger.error("{}: Niewłaściwy stan", getName());
		}
	}
	
	public boolean doPreVerify() {
		if(status == PATROL) {
			status = PRE_VERIFY;
			
			logger.debug("{}: Zmiana stanu na PRE_VERIFY", getName());
			log("Zmiana stanu na PRE_VERIFY");
			
			removeBehaviour(patrol);
			return true;
		} 
		
		return false;
	}
	
	public void doVerify(PositionMessage pm) {
		if(status == PRE_VERIFY) {
			status = VERIFY;		
		
			logger.debug("{}: Zmiana stanu na VERIFY", getName());
			log("Zmiana stanu na VERIFY");
			
			addBehaviour(new VerifyBehaviour(this, pm.getAID(), pm.getPosition()));
		} else {
			logger.error("{}: Niewłaściwy stan", getName());
		}
	}
	
	public void doBroadCast() {
		status = BROADCAST;
		
		logger.debug("{}: Zmiana stanu na BROADCAST", getName());
		log("Zmiana stanu na BROADCAST");
				
		addBehaviour(new BroadcastDeerPositionBehaviour(this));
	}
	
	//
	// Akcesory
	//
	
	public int getStatus() {
		return this.status;
	}
	
	public int getHelicopterCount() {
		return this.agentCount;
	}
	
	public void setSearchArea(Area searchArea) {
		this.searchArea = searchArea;
	}

	public HashSet<PositionMessage> getAgents() {
		return this.agents;
	}
	
	//
	// Kolorki
	//
	
	public void setColor() {
		r = AgentColor.HELICOPTER_COLOR[0];
		g = AgentColor.HELICOPTER_COLOR[1];
		b = AgentColor.HELICOPTER_COLOR[2];
	}
	
	public void setPatrolColor() {
		r = AgentColor.HELICOPTER_PATROL_COLOR[0];
		g = AgentColor.HELICOPTER_PATROL_COLOR[1];
		b = AgentColor.HELICOPTER_PATROL_COLOR[2];
	}
	
	public void setCheckColor() {
		r = AgentColor.HELICOPTER_CHECK_COLOR[0];
		g = AgentColor.HELICOPTER_CHECK_COLOR[1];
		b = AgentColor.HELICOPTER_CHECK_COLOR[2];
	}
	
	public void setFollowColor() {
		r = AgentColor.HELICOPTER_FOLLOW_COLOR[0];
		g = AgentColor.HELICOPTER_FOLLOW_COLOR[1];
		b = AgentColor.HELICOPTER_FOLLOW_COLOR[2];		
	}
	
	public void setVerifyColor() {
		r = AgentColor.HELICOPTER_VERIFY_COLOR[0];
		g = AgentColor.HELICOPTER_VERIFY_COLOR[1];
		b = AgentColor.HELICOPTER_VERIFY_COLOR[2];		
	}
}
